package com.sky.config;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.sky.constant.CacheConstant;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cache.annotation.EnableCaching;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching // 开启 Spring Cache 注解支持
public class CacheConfiguration{

    // 1. 定义业务缓存策略
    // 普通缓存：基础1小时 + 0-10分钟随机（避免雪崩）
    private static final long BASE_TTL = 1; // 基础过期时间（小时）
    private static final int RANDOM_MIN = 10; // 随机偏移（分钟）
    // 热门缓存：基础6小时 + 0-30分钟随机（减少击穿）
    private static final long HOT_BASE_TTL = 6;
    private static final int HOT_RANDOM_MIN = 30;

    //2. 配置缓存管理器（核心：管理所有缓存）
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List<CaffeineCache> caches = new ArrayList<>();

        /**
         * 构建缓存实例
         */
        caches.add(buildCache(CacheConstant.DISH_CACHE, BASE_TTL, RANDOM_MIN)); //菜品缓存
        caches.add(buildCache(CacheConstant.HOT_DISH_ID_CACHE, HOT_BASE_TTL, HOT_RANDOM_MIN)); //热门菜品id缓存
        caches.add(buildCache(CacheConstant.DISH_PAGE_CACHE, BASE_TTL, RANDOM_MIN));//菜品分页缓存
        caches.add(buildCache(CacheConstant.DISH_CATEGORY_CACHE, BASE_TTL, RANDOM_MIN));//菜品分类缓存
        caches.add(buildCache(CacheConstant.CATEGORY_LIST_CACHE, BASE_TTL, RANDOM_MIN));//根据类型查询分类缓存
        caches.add(buildCache(CacheConstant.CATEGORY_CACHE, BASE_TTL, RANDOM_MIN));//分类缓存
        caches.add(buildCache(CacheConstant.CATEGORY_PAGE_CACHE, BASE_TTL, RANDOM_MIN));//分类分页缓存
        caches.add(buildCache(CacheConstant.SETMEAL_CACHE, BASE_TTL, RANDOM_MIN));//套餐缓存
        caches.add(buildCache(CacheConstant.HOT_SETMEAL_ID_CACHE, HOT_BASE_TTL, HOT_RANDOM_MIN));//热门套餐id缓存
        caches.add(buildCache(CacheConstant.SETMEAL_PAGE_CACHE, BASE_TTL, RANDOM_MIN));//套餐分页缓存
        caches.add(buildCache(CacheConstant.SHOPPING_CART_CACHE, BASE_TTL, RANDOM_MIN));//购物车缓存
        caches.add(buildCache(CacheConstant.SETMEAL_CATEGORY_CACHE, BASE_TTL, RANDOM_MIN));//根据分类id查询套餐缓存
        cacheManager.setCaches(caches);
        return cacheManager;
    }

    //3. 工具方法：构建带随机过期的缓存（解决雪崩的关键）
    /**
     * 生成 Caffeine 缓存实例
     * @param cacheName 缓存名称（如 "dishCache"）
     * @param baseTtlHours 基础过期时间（小时）
     * @param randomMin 随机偏移（分钟，0~randomMin）
     */
    private CaffeineCache buildCache(String cacheName, long baseTtlHours, int randomMin) {
        // 1. 计算总过期时间 = 基础时间 + 随机偏移（避免大量缓存同时过期）
        int random = new Random().nextInt(randomMin); // 0~randomMin 分钟的随机值
        long totalTtlMinutes = baseTtlHours * 60 + random; // 转成分钟

        // 2. 配置 Caffeine 缓存规则
        Cache<Object, Object> caffeineCache = Caffeine.newBuilder()
                .expireAfterWrite(totalTtlMinutes, TimeUnit.MINUTES) // 写入后过期（防雪崩）
                .maximumSize(10_000) // 最大缓存1万条（防内存溢出，适配你的菜品数量）
                .recordStats() // 记录缓存命中率（可选，用于调优）
                .build(); // 生成实际的缓存实例

        // 3. 包装成 Spring Cache 能识别的 CaffeineCache
        return new CaffeineCache(cacheName, caffeineCache);
    }
}